package org.rich.charlesmurphy.core.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.ddevil.data.BasicData;
import org.ddevil.data.Data;
import org.ddevil.data.set.BeanDataSet;
import org.rich.charlesmurphy.core.CMIds;
import org.rich.charlesmurphy.core.ParseResult;
import org.rich.charlesmurphy.core.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Parser that will parse web server access logs.
 * @author Rich
 */
public class AccessLogParser implements Parser {

	private Logger log = LoggerFactory.getLogger(getClass());

	private String logFormat;
	private Pattern pattern;

	private Map<String, String> formatTokensToIds;
	private Map<String, Integer> idsToGroupIndex;

	public AccessLogParser(String logFormat) {
		formatTokensToIds = new HashMap<String, String>();
		formatTokensToIds.put("%h", CMIds.REMOTE_HOST);
		formatTokensToIds.put("%t", CMIds.TIME);
		formatTokensToIds.put("%r", CMIds.REQUEST_FIRST_LINE);
		formatTokensToIds.put("%s", CMIds.STATUS);
		formatTokensToIds.put("%b", CMIds.RESPONSE_BODY_SIZE);

		setLogFormat(logFormat);
	}

	/**
	 * @param logFormat the logFormat to set
	 */
	public void setLogFormat(String logFormat) {
		this.logFormat = logFormat;
		pattern = Pattern.compile(buildRegExFromFormat(logFormat));
	}


	// TODO parse a CLF format string and building a reg ex for parsing...
	// a work in progresss

	private String buildRegExFromFormat(String format) {
		/*
		String[] tokens = format.split(" ");
		for (int i = 0; i < tokens.length; i++) {

		}
		*/

		idsToGroupIndex = new HashMap<String, Integer>();
		idsToGroupIndex.put(CMIds.REMOTE_HOST, 1);
		idsToGroupIndex.put(CMIds.TIME, 4);
		idsToGroupIndex.put(CMIds.REQUEST_FIRST_LINE, 5);
		idsToGroupIndex.put(CMIds.STATUS, 6);
		idsToGroupIndex.put(CMIds.RESPONSE_BODY_SIZE, 7);

		// format: "%h %l %u %t \"%r\" %>s %b"
		return "^(\\S+) (\\S+) (\\S+) \\[(.+)\\] \"(.+)\" (\\S+) (\\S+)$";
//		return "(\\S+) (\\S+) (\\S+) (\\[.+\\]) (\".+\") (\\d+) (\\d+)";

//		return "^(\\S) (\\S) (\\S) (\\[.+\\]) (\".+\") (\\d*) (\\d*)$";
	}

	private boolean isTokenUsed(String token) {
		Pattern p = Pattern.compile("^%\\>?\\<?(\\{.*\\})?([a-zA-Z]{1})$");

		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	public ParseResult parse(File file) {

		Matcher matcher = null;

		BeanDataSet<Data> ret = new BeanDataSet<Data>();
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));

			String line;
			while ((line = reader.readLine()) != null) {
				line = line.trim();
				matcher = pattern.matcher(line);
				if (matcher.matches()) {

					BasicData data = new BasicData();

					for (String id : idsToGroupIndex.keySet()) {

						String d = matcher.group(idsToGroupIndex.get(id));
						data.addItem(id, !d.equals("-") ? d : null);
					}
					log.trace("Parsed record: {}", data);
					ret.importRecord(data);
				}
				else {
					log.debug("Line could not be parsed, did not match regex. Regex=[{}] Line=[{}]",pattern.pattern(), line);
				}

			}


		} catch (FileNotFoundException e) {
			throw new RuntimeException("Can't parse file cause we can't find it.", e);

		} catch (IOException e) {
			throw new RuntimeException("Isssue reading from file.", e);
		}

		log.debug("Parsed access log.  Found [{}] records.", ret.size());

		return new ParseResult(ret, null);
	}



}
